package com.example.supernote.ui.note.components

import android.Manifest
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardVoice
import androidx.compose.material.icons.filled.Upload
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import com.example.supernote.R
import com.example.supernote.ui.components.UniformButton
import com.example.supernote.ui.components.UniformDialog
import com.example.supernote.ui.components.UniformPreviewBody
import com.example.supernote.ui.components.UniformPreviewFooter
import com.example.supernote.ui.components.UniformProgressBar
import com.example.supernote.ui.components.UniformToast
import com.example.supernote.ui.note.utils.SelectAudioContract
import com.example.supernote.ui.note.utils.getFinalTemplate
import com.example.supernote.ui.utils.getPermissionLauncher
import com.example.supernote.ui.utils.getShowInfos
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.io.File

@Composable
fun ChangeAudioToText(
    onCancel: () -> Unit,
    onGenerate: (updateTemplate: (String) -> Unit, updateProgress: (Float) -> Unit, Uri, android.content.Context) -> Unit,
    onConfirm: (ocrText: String) -> Unit
) {
    // 音频
    var audioUri: Uri? by remember { mutableStateOf(null) }
    val dialogTitle = stringResource(R.string.note_convert_audio)
    var isGenerated by remember { mutableStateOf(false) }
    val showInfos = getShowInfos(dialogTitle)
    var uploadPreview by remember { mutableStateOf(false) }
    var cameraPreview by remember { mutableStateOf(false) }
    var showAudioRecorder by remember { mutableStateOf(false) }
    var showGetorDialog by remember { mutableStateOf(true) }
    var template by remember { mutableStateOf("") }
    var curProgress by remember { mutableFloatStateOf(0f) }
    val scope = rememberCoroutineScope()
    val context = LocalContext.current

    val cameraFunction: (Uri) -> Unit = {
        template = ""
        audioUri = it
        cameraPreview = true
        uploadPreview = false
    }

    if (showAudioRecorder) {
        val cancelInfo = stringResource(R.string.note_recorder_cancel)
        AudioRecorder(
            getFilePath = {
                it?.let { cameraFunction(Uri.fromFile(File(it))); template = "" }
                    ?: run { UniformToast(context, cancelInfo) }
            },
            onCancel = { showAudioRecorder = false; showGetorDialog = true }
        )
    } else {
        UniformDialog(
            title = dialogTitle,
            body = {
                val uploadLauncher =
                    rememberLauncherForActivityResult(contract = SelectAudioContract()) {
                        it?.let { uri ->
                            template = ""
                            uploadPreview = true
                            audioUri = uri
                        }
                        showGetorDialog = true
                    }
                val uploadPermission =
                    getPermissionLauncher({ uploadLauncher.launch(null); showGetorDialog = false })
                val cameraPermission = getPermissionLauncher({ showAudioRecorder = true })

                if (uploadPreview || cameraPreview) {
                    if (showGetorDialog && template.isEmpty()) {
                        UniformPreviewBody(
                            title = stringResource(R.string.note_preview_select),
                            sourceUri = audioUri,
                            method = "audio"
                        )
                    } else {
                        val getHtml: @Composable () -> String = {
                            val ctx = com.example.supernote.model.note.context.Context()
                            ctx.article = TextFieldValue(getFinalTemplate(template))
                            ctx.parseContext()
                        }

                        UniformPreviewBody(
                            title = stringResource(R.string.note_preview_result),
                            html = getHtml()
                        )
                    }
                    if (isGenerated) {
                        UniformProgressBar(
                            if (curProgress < 0.5) stringResource(R.string.note_audio_uploading) else stringResource(
                                R.string.note_audio_parsing
                            ),
                            "liner", "finite", curProgress
                        )
                    }
                }
                if (!isGenerated) {
                    Row {
                        UniformButton(
                            modifier = Modifier.weight(1f),
                            onClick = { uploadPermission.launch(Manifest.permission.READ_EXTERNAL_STORAGE) },
                            imageVector = Icons.Filled.Upload,
                            text = if (uploadPreview) stringResource(R.string.note_upload_after) else stringResource(
                                R.string.note_upload_before
                            )
                        )
                        Spacer(modifier = Modifier.width(5.dp))
                        UniformButton(
                            modifier = Modifier.weight(1f),
                            onClick = { cameraPermission.launch(Manifest.permission.RECORD_AUDIO) },
                            imageVector = Icons.Filled.KeyboardVoice,
                            text = if (cameraPreview) stringResource(R.string.note_take_audio_after) else stringResource(
                                R.string.note_take_audio_before
                            )
                        )
                    }
                }
            }
        ) {
            val warn = stringResource(R.string.note_text_warning)
            var job1: Job? = null
            var job2: Job? = null  // 防止运行过程中出现错误
            UniformPreviewFooter(
                template = template,
                isGenerated = isGenerated,
                aiMode = showInfos["aiMode"]!!,
                confirmButtonText = showInfos["confirmButtonText"]!!,
                onCancel = onCancel,
                onConfirm = {
                    onConfirm(template)
                    UniformToast(context, showInfos["resultTip"]!!)
                },
                onGenerate = {
                    audioUri?.let {
                        template = ""
                        isGenerated = true
                        onGenerate(
                            {
                                val func: () -> Unit = {
                                    job1?.cancel()
                                    template = it
                                    isGenerated = false
                                    curProgress = 0f
                                }
                                if (listOf("Network Error", "Format Error").contains(it)) {
                                    func()
                                    job2?.cancel()
                                } else {
                                    job2 = scope.launch(Dispatchers.IO) {
                                        while (1 - curProgress > 0.005) {
                                        }
                                        func()
                                    }
                                }
                            },
                            {
                                job1?.cancel()
                                job1 = scope.launch(Dispatchers.IO) {
                                    val temp = curProgress
                                    while (it - curProgress >= 0.005) {
                                        val step =
                                            if (it > 0.5) (it - temp) / 10f else (it - curProgress) / 50f
                                        curProgress += step
                                        delay(100L)
                                    }
                                }
                            },
                            audioUri!!,
                            context
                        )
                    } ?: run {
                        UniformToast(context, warn)
                    }
                }
            )
        }
    }
}